package com.lry.pda.bottom.operation;



import com.lry.pda.topdown.SymbolDefine;

import java.util.Iterator;
import java.util.List;
import java.util.Map;


public class FirstSetBuilder {
	
    private Map<Integer, Symbols> symbolMap;
    private boolean runFirstSetPass = true;


    public FirstSetBuilder() {
    	this.symbolMap = Grammar.getSelf().getSymbolMap();
    }

    public boolean isSymbolNullable(int sym) {
    	Symbols symbol= symbolMap.get(sym);
    	if (symbol == null) {
    		return false;
    	}

    	return symbol.isNullable ? true : false;
    }


    public void runFirstSets() {
    	while (runFirstSetPass) {
    		runFirstSetPass = false;

    		Iterator<Symbols> it = symbolMap.values().iterator();
    		while (it.hasNext()) {
    			Symbols symbol = it.next();
    			addSymbolFirstSet(symbol);
    		}
    	}
    	printAllFirstSet();
		System.out.println("============");
    }

    private void addSymbolFirstSet(Symbols symbol) {
    	if (isSymbolTerminals(symbol.value) == true) {
    		if (symbol.firstSet.contains(symbol.value) == false) {
    			symbol.firstSet.add(symbol.value);
    		}
    		return;
    	}

    	for (int i = 0;  i < symbol.productions.size(); i++) {
    		List<Integer> rights = symbol.productions.get(i);
    		if (null==rights||rights.isEmpty()) {
    			continue;
    		}
    		Integer firstSymbol = rights.get(0);
    		if (isSymbolTerminals(firstSymbol) && !symbol.firstSet.contains(firstSymbol)) {
    			runFirstSetPass = true;
    			symbol.firstSet.add(firstSymbol);
    		}
    		else if (!isSymbolTerminals(firstSymbol)) {
    			//add first set of nullable
    			int pos = 0;
    			Symbols curSymbol = null;
    			do {
    				curSymbol = symbolMap.get(rights.get(pos));
    				if (symbol.firstSet.containsAll(curSymbol.firstSet) == false) {
    					runFirstSetPass = true;

    					for (int j = 0; j < curSymbol.firstSet.size(); j++) {
    						if (symbol.firstSet.contains(curSymbol.firstSet.get(j)) == false) {
    							symbol.firstSet.add(curSymbol.firstSet.get(j));
    						}
    					}//for (int j = 0; j < curSymbol.firstSet.size(); j++)

    				}//if (symbol.firstSet.containsAll(curSymbol.firstSet) == false)

    				pos++;
    			}while(pos < rights.size() && curSymbol.isNullable);
    		} // else

    	}//for (int i = 0; i < symbol.productions.size(); i++)
    }

    private boolean isSymbolTerminals(int symbol) {
    	return symbol < 256;
    }

    public void printAllFirstSet() {
    	Iterator<Symbols> it = symbolMap.values().iterator();
		while (it.hasNext()) {
		    Symbols sym = it.next();
		    printFirstSet(sym);
		}
    }

    private void printFirstSet(Symbols symbol) {

    	String s = SymbolDefine.getSymbolStr(symbol.value);
    	s += "{ ";
    	for (int i = 0; i < symbol.firstSet.size(); i++) {
    		s += SymbolDefine.getSymbolStr(symbol.firstSet.get(i)) + " ";
    	}
    	s += " }";

    	System.out.println(s);
    	System.out.println("============");
    }

    public List<Integer> getFirstSet(int symbol) {
    	Iterator<Symbols> it = symbolMap.values().iterator();
		while (it.hasNext()) {
		    Symbols sym = it.next();
		    if (sym.value == symbol) {
		    	return sym.firstSet;
		    }
		}
		return null;
	
    }
    
 
}
